package com.qding.cupms.admin.rest.controller;

import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.qding.cupms.admin.rest.client.ClientHelper;
import com.qding.cupms.admin.rest.redis.SessionRedisTemplate;
import com.qding.cupms.admin.rest.shiro.ShiroRedisSessionDao;
import com.qding.cupms.common.constant.Constant;
import com.qding.cupms.common.enums.TokenStatuEnum;
import com.qding.cupms.common.model.AnswerMsg;
import com.qding.cupms.common.model.AnswerMsgFactoryImpl;
import com.qding.cupms.common.model.ResponseCodeEnum;
import com.qding.cupms.common.model.ReturnDataResult;
import com.qding.cupms.common.model.SSOClientInfo;
import com.qding.cupms.common.model.SSOSystemInfo;
import com.qding.cupms.common.model.SSOUserinfo;
import com.qding.cupms.common.utils.JsonUtil;

import io.swagger.annotations.Api;

/**
 * SSO 单点登录 控制器
 * 
 * @since [基础数据/单点登录]
 * @author ly
 * @version v1.0 Date:2017年8月9日 上午9:42:52
 */
@RestController
@RequestMapping("/SSO")
@Api(value = "单点登录管理", description = "单点登录管理")
public class SSOController extends BaseController {

    private Logger _log = LoggerFactory.getLogger(SSOController.class);

    // /**
    // * redisTemplate redis操作
    // */
    // @Autowired
    // private SessionRedisTemplate redisTemplate;

    @Autowired
    private ShiroRedisSessionDao shiroRedisSessionDao;

    /**
     * 单点登录
     * 
     * @param account
     *            账号
     * @param password
     *            密码
     * @param request
     * @param response
     * @return
     * @author ly Date:2017年8月10日 下午2:46:42
     */
    @RequestMapping(value = "/signin", method = RequestMethod.POST)
    public AnswerMsg signin(String account, String password, HttpServletRequest request, HttpServletResponse response) {

        if ("admin".equals("admin") && "123456".equals(password)) {

            // 创建全局会话
            Session session = SecurityUtils.getSubject().getSession();
            String token = session.getId().toString();

            // 初妈化用户信息到全局会话当中
            SSOUserinfo ssoUserinfo = new SSOUserinfo();
            ssoUserinfo.setAccount("admin");
            ssoUserinfo.setPassword("123456");
            ssoUserinfo.setRealName("雷阳");
            ssoUserinfo.setStatus("0");
            ssoUserinfo.setTenantId("XXXXXXXX");
            session.setAttribute(Constant.GLOBAL_SESSION_USER_KEY, ssoUserinfo);

            _log.debug("####账号认证通过,SSOUserinfo:{}", JsonUtil.Java2Json(ssoUserinfo));
            // 返回受权令牌
            AnswerMsg answerMsg = AnswerMsgFactoryImpl.createSuccessAnserMsg("登录成功");
            ReturnDataResult dataResutl = ReturnDataResult.createObjDate();
            dataResutl.putDataOnObj("token", token);
            answerMsg.setData(dataResutl.getData());

            return answerMsg;
        } else {
            return AnswerMsgFactoryImpl.createErrorAnserMsg(ResponseCodeEnum.AUTH.getValue(), "账号认证失败");

        }

    }

    /**
     * 令牌验证
     * 
     * @param token
     *            令牌
     * @param serverUri
     *            客户端系统接口地址
     * @param logoutUri
     *            注销接口地址
     * @param clearSessionUri
     *            清除局部会话接口地址
     * @param request
     * @param response
     * @return
     * @author Administrator Date:2017年8月10日 下午4:57:46
     */
    @RequestMapping(value = "/checkToken", method = RequestMethod.POST)
    public AnswerMsg checkToken(@RequestHeader(required = true, value = "token") String token,
            @RequestParam(required = true, value = "serverUri") String serverUri,
            @RequestParam(required = true, value = "logoutUri") String logoutUri, HttpServletRequest request,
            HttpServletResponse response) {
        Session session = effectiveToken(token);
        AnswerMsg answerMsg = null;
        if (session == null) {
            // token不合法
            ReturnDataResult dataResult = ReturnDataResult.createObjDate();
            dataResult.putDataOnObj("status", TokenStatuEnum.WRONGFUL.getValue());
            answerMsg = AnswerMsgFactoryImpl.createAnswerMsg(dataResult.getData());
            answerMsg.setMsg("token检查不合法,请重新获取");
            return answerMsg;
        }

        // 注册系统
        SSOClientInfo clientInfo = new SSOClientInfo();
        clientInfo.setServerUri(serverUri);
        clientInfo.setLogoutUri(logoutUri);
        registerClient(session, clientInfo);

        _log.debug("session:{},userInfo:{},systemInfo:{}", session.toString());
        ReturnDataResult dataResult = ReturnDataResult.createObjDate();
        dataResult.putDataOnObj("status", TokenStatuEnum.LEGITIMATE.getValue());
        dataResult.putDataOnObj("userInfo", session.getAttribute(Constant.GLOBAL_SESSION_USER_KEY));
        answerMsg = AnswerMsgFactoryImpl.createAnswerMsg(dataResult.getData());
        return answerMsg;
    }

    /**
     * 注册系统 注册系统
     * 
     * @param session
     * @param clientInfo
     * @author Administrator Date:2017年8月10日 下午5:34:01
     */
    private void registerClient(Session session, SSOClientInfo clientInfo) {

        SSOSystemInfo systemInfo = (SSOSystemInfo) session.getAttribute(Constant.GLOBAL_SESSION_CLIENT_SYS_KEY);
        String logoutUri = clientInfo.getLogoutUri();
        String serverUri = clientInfo.getServerUri();
        if (systemInfo == null) {
            // 第一个注册系统
            systemInfo = new SSOSystemInfo();
            systemInfo.getClientclientMap().put(serverUri, clientInfo);
            systemInfo.setUpdateTime(new Date());
            session.setAttribute(Constant.GLOBAL_SESSION_CLIENT_SYS_KEY, systemInfo);
        } else {
            if (!systemInfo.getClientclientMap().containsKey(serverUri)) {
                systemInfo.getClientclientMap().put(serverUri, clientInfo);
                systemInfo.setUpdateTime(new Date());
            }
        }

        this.shiroRedisSessionDao.update(session);
        // SecurityUtils.getSecurityManager().ses
        // //更新会话
        // redisTemplate.opsForValue().set(ShiroRedisSessionDao.getStringKey(session.getId()), session);

    }

    /**
     * 检查令牌是否有效
     * 
     * @param token
     *            令牌
     * @return Session null 无效, 有值 有效
     * @author Administrator Date:2017年8月10日 下午5:04:43
     */
    private Session effectiveToken(String token) {
        try {
            Session session = this.shiroRedisSessionDao.readSession(token);
            _log.debug("getSession:{}", JsonUtil.Java2Json(session));
            if (session != null && session.getAttribute(Constant.GLOBAL_SESSION_USER_KEY) != null) {
                return session;
            }
        } catch (UnknownSessionException e) {

            return null;
        }
        return null;
    }

    /**
     * 注销令牌
     * 
     * @param token
     *            令牌
     * @param request
     * @param response
     * @return
     * @author ly Date:2017年8月10日 下午2:50:46
     */
    @RequestMapping(value = "/cancel", method = RequestMethod.POST)
    public AnswerMsg cancel(@RequestHeader(value = "token") String token, HttpServletRequest request,
            HttpServletResponse response) {

        Session session = this.effectiveToken(token);
        AnswerMsg answerMsg = null;
        if (session == null) {
            // token不合法
            answerMsg = AnswerMsgFactoryImpl.createSuccessAnserMsg("token不存在,注销成功!");
            return answerMsg;
        }

        // 查询客户端系统会话
        SSOSystemInfo systemInfo = (SSOSystemInfo) session.getAttribute(Constant.GLOBAL_SESSION_CLIENT_SYS_KEY);
        // 注销全局会话
        shiroRedisSessionDao.deleteById(token);

        if (systemInfo != null) {
            for (Map.Entry<String, SSOClientInfo> entry : systemInfo.getClientclientMap().entrySet()) {
                ClientHelper.logout(entry.getValue(), token);
            }
        }

        return AnswerMsgFactoryImpl.createSuccessAnserMsg("OK");
    }

}
